From de7e7ca26fb57f75272985ba38fbd2ad9d97acd0 Mon Sep 17 00:00:00 2001 From: "kaf24@scramble.cl.cam.ac.uk" Date: Sun, 29 Feb 2004 17:45:39 +0000 Subject: [PATCH] bitkeeper revision 1.757 (40422543Wg1i77yDldDqmAGZ6DVnnQ) xl_evtchn.c, event_channel.h, event_channel.c, Xc.c, xc.h: Cleanups and fixes for event channels. --- tools/xc/lib/xc.h | 2 +- tools/xc/py/Xc.c | 10 +- xen/common/event_channel.c | 18 +- xen/include/hypervisor-ifs/event_channel.h | 2 +- .../arch/xeno/drivers/evtchn/xl_evtchn.c | 189 ++++++++++++------ 5 files changed, 142 insertions(+), 79 deletions(-) diff --git a/tools/xc/lib/xc.h b/tools/xc/lib/xc.h index 2200177932..907aa56c30 100644 --- a/tools/xc/lib/xc.h +++ b/tools/xc/lib/xc.h @@ -162,7 +162,7 @@ int xc_vbd_probe(int xc_handle, #define EVTCHNSTAT_connected 2 /* Channel is connected to remote. */ int xc_evtchn_open(int xc_handle, u64 dom1, /* may be DOMID_SELF */ - u64 dom2, + u64 dom2, /* may be DOMID_SELF */ int *port1, int *port2); int xc_evtchn_close(int xc_handle, diff --git a/tools/xc/py/Xc.c b/tools/xc/py/Xc.c index fe29da1cde..7ee540afc5 100644 --- a/tools/xc/py/Xc.c +++ b/tools/xc/py/Xc.c @@ -772,13 +772,13 @@ static PyObject *pyxc_evtchn_open(PyObject *self, XcObject *xc = (XcObject *)self; PyObject *dict; - u64 dom1 = DOMID_SELF, dom2; + u64 dom1 = DOMID_SELF, dom2 = DOMID_SELF; int port1, port2, ret; - static char *kwd_list[] = { "dom2", "dom1", NULL }; + static char *kwd_list[] = { "dom1", "dom2", NULL }; - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "L|L", kwd_list, - &dom2, &dom1) ) + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|LL", kwd_list, + &dom1, &dom2) ) { DPRINTF("could not parse parameter list."); return NULL; @@ -1163,7 +1163,7 @@ static PyMethodDef pyxc_methods[] = { METH_VARARGS | METH_KEYWORDS, "\n" "Open an event channel between two domains.\n" " dom1 [long, SELF]: First domain to be connected.\n" - " dom2 [long]: Second domain to be connected.\n\n" + " dom2 [long, SELF]: Second domain to be connected.\n\n" "Returns: [dict] dictionary is empty on failure.\n" " port1 [int]: Port-id for endpoint at dom1.\n" " port2 [int]: Port-id for endpoint at dom2.\n" }, diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index 5812109ae6..919e9855cc 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -92,15 +92,10 @@ static long event_channel_open(evtchn_open_t *open) if ( !IS_PRIV(current) ) return -EPERM; - /* 'dom1' may be DOMID_SELF. 'dom2' cannot be.*/ if ( dom1 == DOMID_SELF ) dom1 = current->domain; if ( dom2 == DOMID_SELF ) - return -EINVAL; - - /* Event channel must connect distinct domains. */ - if ( dom1 == dom2 ) - return -EINVAL; + dom2 = current->domain; if ( ((p1 = find_domain_by_id(dom1)) == NULL) || ((p2 = find_domain_by_id(dom2)) == NULL) ) @@ -118,7 +113,8 @@ static long event_channel_open(evtchn_open_t *open) } else { - spin_lock(&p2->event_channel_lock); + if ( p1 != p2 ) + spin_lock(&p2->event_channel_lock); spin_lock(&p1->event_channel_lock); } @@ -148,7 +144,8 @@ static long event_channel_open(evtchn_open_t *open) out: spin_unlock(&p1->event_channel_lock); - spin_unlock(&p2->event_channel_lock); + if ( p1 != p2 ) + spin_unlock(&p2->event_channel_lock); put_task_struct(p1); put_task_struct(p2); @@ -191,7 +188,7 @@ static long __event_channel_close(struct task_struct *p1, int port1) { spin_lock(&p2->event_channel_lock); } - else + else if ( p1 != p2 ) { spin_unlock(&p1->event_channel_lock); spin_lock(&p2->event_channel_lock); @@ -234,7 +231,8 @@ static long __event_channel_close(struct task_struct *p1, int port1) if ( p2 != NULL ) { - spin_unlock(&p2->event_channel_lock); + if ( p1 != p2 ) + spin_unlock(&p2->event_channel_lock); put_task_struct(p2); } diff --git a/xen/include/hypervisor-ifs/event_channel.h b/xen/include/hypervisor-ifs/event_channel.h index 573953d246..159f146b2f 100644 --- a/xen/include/hypervisor-ifs/event_channel.h +++ b/xen/include/hypervisor-ifs/event_channel.h @@ -12,7 +12,7 @@ /* * EVTCHNOP_open: Open a communication channel between and . * NOTES: - * 1. may be specified as DOMID_SELF. + * 1. and/or may be specified as DOMID_SELF. * 2. Only a sufficiently-privileged domain may create an event channel. * 3. and are only supplied if the op succeeds. */ diff --git a/xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/xl_evtchn.c b/xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/xl_evtchn.c index 82af52ec8c..1bfd377f9a 100644 --- a/xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/xl_evtchn.c +++ b/xenolinux-2.4.25-sparse/arch/xeno/drivers/evtchn/xl_evtchn.c @@ -30,6 +30,10 @@ typedef void (*evtchn_receiver_t)(unsigned int); /* /dev/xeno/evtchn resides at device number major=10, minor=200 */ #define EVTCHN_MINOR 200 +/* /dev/xeno/evtchn ioctls: */ +/* EVTCHN_RESET: Clear and reinit the event buffer. Clear error condition. */ +#define EVTCHN_RESET _IO('E', 1) + /* NB. This must be shared amongst drivers if more things go in /dev/xeno */ static devfs_handle_t xeno_dev_dir; @@ -37,8 +41,10 @@ static devfs_handle_t xeno_dev_dir; static unsigned long evtchn_dev_inuse; /* Notification ring, accessed via /dev/xeno/evtchn. */ +#define RING_SIZE 2048 /* 2048 16-bit entries */ +#define RING_MASK(_i) ((_i)&(RING_SIZE-1)) static u16 *ring; -static unsigned int ring_cons, ring_prod; +static unsigned int ring_cons, ring_prod, ring_overflow; /* Processes wait on this queue via /dev/xeno/evtchn when ring is empty. */ static DECLARE_WAIT_QUEUE_HEAD(evtchn_wait); @@ -146,11 +152,18 @@ static inline void process_bitmask(u32 *sel, } else if ( ring != NULL ) { - ring[ring_prod] = (u16)(port | port_subtype); - if ( ring_cons == ring_prod++ ) + if ( (ring_prod - ring_cons) < RING_SIZE ) + { + ring[RING_MASK(ring_prod)] = (u16)(port | port_subtype); + if ( ring_cons == ring_prod++ ) + { + wake_up_interruptible(&evtchn_wait); + kill_fasync(&evtchn_async_queue, SIGIO, POLL_IN); + } + } + else { - wake_up_interruptible(&evtchn_wait); - kill_fasync(&evtchn_async_queue, SIGIO, POLL_IN); + ring_overflow = 1; } } } @@ -178,21 +191,62 @@ static void evtchn_interrupt(int irq, void *dev_id, struct pt_regs *regs) spin_unlock_irqrestore(&lock, flags); } +static void __evtchn_reset_buffer_ring(void) +{ + u32 m; + unsigned int i, j; + + /* Initialise the ring with currently outstanding notifications. */ + ring_cons = ring_prod = ring_overflow = 0; + + for ( i = 0; i < 32; i++ ) + { + m = pend_outstanding[i]; + while ( (j = ffs(m)) != 0 ) + { + m &= ~(1 << --j); + if ( rx_fns[(i * 32) + j] == NULL ) + ring[ring_prod++] = (u16)(((i * 32) + j) | PORT_NORMAL); + } + + m = disc_outstanding[i]; + while ( (j = ffs(m)) != 0 ) + { + m &= ~(1 << --j); + if ( rx_fns[(i * 32) + j] == NULL ) + ring[ring_prod++] = (u16)(((i * 32) + j) | PORT_DISCONNECT); + } + } +} + static ssize_t evtchn_read(struct file *file, char *buf, size_t count, loff_t *ppos) { int rc; + unsigned int c, p, bytes1 = 0, bytes2 = 0; DECLARE_WAITQUEUE(wait, current); add_wait_queue(&evtchn_wait, &wait); + if ( (count <= 0) || (count > PAGE_SIZE) || ((count&1) != 0) ) + { + rc = -EINVAL; + goto out; + } + for ( ; ; ) { set_current_state(TASK_INTERRUPTIBLE); - if ( ring_cons != ring_prod ) + if ( (c = ring_cons) != (p = ring_prod) ) break; + if ( ring_overflow ) + { + rc = -EFBIG; + goto out; + } + if ( file->f_flags & O_NONBLOCK ) { rc = -EAGAIN; @@ -208,11 +262,35 @@ static ssize_t evtchn_read(struct file *file, char *buf, schedule(); } - rc = -EINVAL; - if ( count >= sizeof(ring_prod) ) - rc = put_user(ring_prod, (unsigned int *)buf); - if ( rc == 0 ) - rc = sizeof(ring_prod); + rc = -EFAULT; + + /* Byte length of first chunk. May be truncated by ring wrap. */ + if ( ((c ^ p) & RING_SIZE) != 0 ) + bytes1 = (RING_SIZE - RING_MASK(c)) * sizeof(u16); + else + bytes1 = (p - c) * sizeof(u16); + + /* Further truncate chunk length according to caller's maximum count. */ + if ( bytes1 > count ) + bytes1 = count; + + /* Copy the first chunk. */ + if ( copy_to_user(buf, &ring[c], bytes1) != 0 ) + goto out; + + /* More bytes to copy? */ + if ( count > bytes1 ) + { + bytes2 = RING_MASK(p) * sizeof(u16); + if ( bytes2 > count ) + bytes2 = count; + if ( (bytes2 != 0) && copy_to_user(&buf[bytes1], &ring[0], bytes2) ) + goto out; + } + + ring_cons = (bytes1 + bytes2) / sizeof(u16); + + rc = bytes1 + bytes2; out: __set_current_state(TASK_RUNNING); @@ -223,47 +301,58 @@ static ssize_t evtchn_read(struct file *file, char *buf, static ssize_t evtchn_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { - int rc = -EINVAL; - unsigned int new_cons = 0; + int rc, i; + u16 *kbuf = (u16 *)get_free_page(GFP_KERNEL); - if ( count >= sizeof(new_cons) ) - rc = get_user(new_cons, (unsigned int *)buf); + if ( kbuf == NULL ) + return -ENOMEM; - if ( rc != 0 ) - return rc; + if ( (count <= 0) || (count > PAGE_SIZE) || ((count&1) != 0) ) + { + rc = -EINVAL; + goto out; + } + + if ( copy_from_user(kbuf, buf, count) != 0 ) + { + rc = -EFAULT; + goto out; + } - rc = sizeof(new_cons); + for ( i = 0; i < (count/2); i++ ) + evtchn_clear_port(kbuf[i]); - while ( ring_cons != new_cons ) - evtchn_clear_port(ring[ring_cons++]); + rc = count; + out: + free_page((unsigned long)kbuf); return rc; } +static int evtchn_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + if ( cmd != EVTCHN_RESET ) + return -EINVAL; + + spin_lock_irq(&lock); + __evtchn_reset_buffer_ring(); + spin_unlock_irq(&lock); + + return 0; +} + static unsigned int evtchn_poll(struct file *file, poll_table *wait) { unsigned int mask = POLLOUT | POLLWRNORM; poll_wait(file, &evtchn_wait, wait); if ( ring_cons != ring_prod ) mask |= POLLIN | POLLRDNORM; + if ( ring_overflow ) + mask = POLLERR; return mask; } -static int evtchn_mmap(struct file *file, struct vm_area_struct *vma) -{ - /* Caller must map a single page of memory from 'file offset' zero. */ - if ( (vma->vm_pgoff != 0) || ((vma->vm_end - vma->vm_start) != PAGE_SIZE) ) - return -EINVAL; - - /* Not a pageable area. */ - vma->vm_flags |= VM_RESERVED; - - if ( remap_page_range(vma->vm_start, 0, PAGE_SIZE, vma->vm_page_prot) ) - return -EAGAIN; - - return 0; -} - static int evtchn_fasync(int fd, struct file *filp, int on) { return fasync_helper(fd, filp, on, &evtchn_async_queue); @@ -271,9 +360,7 @@ static int evtchn_fasync(int fd, struct file *filp, int on) static int evtchn_open(struct inode *inode, struct file *filp) { - u16 *_ring; - u32 m; - unsigned int i, j; + u16 *_ring; if ( test_and_set_bit(0, &evtchn_dev_inuse) ) return -EBUSY; @@ -283,30 +370,8 @@ static int evtchn_open(struct inode *inode, struct file *filp) return -ENOMEM; spin_lock_irq(&lock); - ring = _ring; - - /* Initialise the ring with currently outstanding notifications. */ - ring_cons = ring_prod = 0; - for ( i = 0; i < 32; i++ ) - { - m = pend_outstanding[i]; - while ( (j = ffs(m)) != 0 ) - { - m &= ~(1 << --j); - if ( rx_fns[(i * 32) + j] == NULL ) - ring[ring_prod++] = (u16)(((i * 32) + j) | PORT_NORMAL); - } - - m = disc_outstanding[i]; - while ( (j = ffs(m)) != 0 ) - { - m &= ~(1 << --j); - if ( rx_fns[(i * 32) + j] == NULL ) - ring[ring_prod++] = (u16)(((i * 32) + j) | PORT_DISCONNECT); - } - } - + __evtchn_reset_buffer_ring(); spin_unlock_irq(&lock); MOD_INC_USE_COUNT; @@ -335,8 +400,8 @@ static struct file_operations evtchn_fops = { owner: THIS_MODULE, read: evtchn_read, write: evtchn_write, + ioctl: evtchn_ioctl, poll: evtchn_poll, - mmap: evtchn_mmap, fasync: evtchn_fasync, open: evtchn_open, release: evtchn_release -- 2.30.2